home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 34 / Amiga Format CD34 (1998-11-20)(Future Publishing)(GB)[!][Christmas issue].iso / -seriously_amiga- / emulation / afid / afid.c < prev    next >
C/C++ Source or Header  |  1998-10-20  |  38KB  |  1,450 lines

  1. /*
  2.  * afid -- like the Apple ][ program called FID, a file handling utility
  3.  *
  4.  * version 1.1
  5.  *
  6.  * We operate on files which contain entire Apple ][ diskettes from
  7.  * track 0, sector 0 to track 34, sector 15.  To keep things simple,
  8.  * the entire disk image is slurped into memory.  I assume the standard
  9.  * disk geometry of 35 tracks and 16 sectors when initializing, but
  10.  * otherwise the code should operate on different geometries.  Different
  11.  * geometries are a chicken and egg problem as the geometry info is
  12.  * defined to be on track 0x11, sector 0, but you need the sector size
  13.  * to figure out where track 0x11 is!  I have tried to make reasonable
  14.  * extrapolations to account for different geometry sizes (e.g., put
  15.  * as many directory entries per sector as possible).
  16.  *
  17.  * Since I'll want to run this on an MS-DOS machine, I am careful to
  18.  * allocate memory in small chunks, use an ANSI C compiler and use
  19.  * longs when the numbers will get bigger than 16 bits (i.e., the
  20.  * number of bytes per disk).
  21.  *
  22.  *
  23.  * Author: version 1.0.
  24.  *    George Phillips <phillips@cs.ubc.ca>
  25.  *    Department of Computer Science
  26.  *    University of British Columbia
  27.  *
  28.  * New for version 1.1.
  29.  *
  30.  * 1) Added a help message listing the commands.
  31.  * 2) Added the ability to load different file images from within afid,
  32.  *    so you no longer need to exit and enter with a new image.
  33.  * 3) Prompts the user when attempting to exit without saving a changed
  34.  *    disk image.
  35.  * 4) Added new commands like load, type, lock, unlock, rename, delete, list
  36.  *
  37.  * Author: version 1.1.
  38.  *     Peter Nyhlen <pnyhlen@usa.net>
  39.  */
  40.  
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <ctype.h>
  44.  
  45. /* This stuff really belongs in a header file */
  46. /******************* afid.h *******************/
  47. struct track
  48. {
  49.     unsigned char** sector;
  50. };
  51.  
  52. struct disk
  53. {
  54.     int            bytes_per_sector;
  55.     int            sectors_per_track;
  56.     int            tracks_per_disk;
  57.     struct track*    track;
  58. };
  59.  
  60. struct afile
  61. {
  62.     int filetype;
  63.     struct disk* d;
  64.     int ts_s, ts_t, ts_ent, dt_t, dt_s, dt_pos;
  65.     int eof, secgroup, dir_t, dir_s, dir_off;
  66. };
  67.  
  68. /* handy disk address macros for getting at particular bytes and words */
  69. #define byteat(d, t, s, n) ((d)->track[(t)].sector[(s)][(n)])
  70. #define wordat(d, t, s, n) (byteat(d, t, s, n) + byteat(d, t, s, (n) + 1) * 256)
  71.  
  72. /* logical constants */
  73. #define DELETE   'D'
  74. #define UNDELETE 'U'
  75. #ifndef TRUE
  76. #define TRUE 1
  77. #endif
  78. #ifndef FALSE
  79. #define FALSE 0
  80. #endif
  81. /*************** end of afid.h ****************/
  82.  
  83.  
  84. /* Function Prototypes */
  85. void build_disk_mem(struct disk*);
  86. void load_disk(struct disk* d, char*);
  87. void read_disk(struct disk*, FILE*);
  88. void verify_geometry(struct disk*);
  89.  
  90. void list_help_msg();
  91. int confirm_changes(int);
  92.  
  93. void catalog(struct disk*);
  94. int  apptoascii(int), asciitoapp(int);
  95. void* alloc(int);
  96.  
  97. void show_freemap(struct disk*);
  98. int  isfree(struct disk*, int, int);
  99. int  allocate_sector(struct disk*, int*, int*, int);
  100. void alloc_sector(struct disk*, int, int);
  101. void free_sector(struct disk*, int, int);
  102. void zero_sector(struct disk*, int, int);
  103.  
  104. int aopen(struct disk*, char*, struct afile*, char*);
  105. int aclose(struct afile*);
  106. int agetc(struct afile*);
  107. int aputc(struct afile*, int);
  108. long agetw(struct afile*);
  109.  
  110. int isfilename(char*, struct disk*, int, int, int);
  111. void aputfilename(char*, struct disk*, int, int, int);
  112. int tokenize(char* , char** );
  113. void hexdump(FILE*, struct afile*);
  114. int traverse_tsl(struct afile* af, int operation);
  115. int dtraverse_tsl(struct afile* af, int operation);
  116. int utraverse_tsl(struct afile* af, int operation);
  117.  
  118.  
  119. main(int argc, char* argv[])
  120. {
  121.     struct disk d;
  122.     struct afile af;
  123.     int textmode = 0;
  124.     int disk_image_loaded = TRUE;
  125.     int any_unsaved_changes = FALSE;
  126.  
  127.     /* Initialize Disk Structure */
  128.     d.bytes_per_sector = 256;
  129.     d.sectors_per_track = 16;
  130.     d.tracks_per_disk = 35;
  131.     build_disk_mem(&d);
  132.  
  133.     /* Process Arguments */
  134.     switch (argc)
  135.     {
  136.     case 1:
  137.         disk_image_loaded = FALSE;
  138.         list_help_msg();
  139.         break;
  140.     case 2:
  141.         load_disk(&d, argv[1]);
  142.         break;
  143.     default:
  144.         fprintf(stderr, "usage: afid disk-image-file\n");
  145.         exit(1);
  146.     }
  147.  
  148.     /* Loop Through Interactive Command Processing */
  149.     for (;;)
  150.     {
  151.     char buf[1024], *arg[10], *p, *cmd;
  152.  
  153.     /* Command Line Prompt */
  154.     printf("] ");
  155.     fflush(stdout);
  156.  
  157.     /* Get User Input */
  158.     if (!fgets(buf, 1024, stdin))
  159.         break;
  160.  
  161.     /* Parse Command Line */
  162.     tokenize(buf, arg);
  163.     cmd = arg[0];
  164.     if (!*cmd)
  165.         continue;
  166.  
  167.     /* Process Command */
  168.     if (!strcmp(cmd, "load"))
  169.     {
  170.         if (confirm_changes(any_unsaved_changes))
  171.         {
  172.         load_disk(&d, arg[1]);
  173.         disk_image_loaded = TRUE;
  174.         }
  175.     }
  176.     else if (!strcmp(cmd, "help"))
  177.         list_help_msg();
  178.     else if (!strcmp(cmd, "quit") || !strcmp(cmd, "exit"))
  179.     {
  180.         if (confirm_changes(any_unsaved_changes))
  181.         break;
  182.     }
  183.     else if (!disk_image_loaded)
  184.         fprintf(stderr, "no disk image loaded.\nunable to execute %s\n", cmd);
  185.     else if (!strcmp(cmd, "catalog"))
  186.         catalog(&d);
  187.     else if (!strcmp(cmd, "free"))
  188.         show_freemap(&d);
  189.     else if (!strcmp(cmd, "text"))
  190.         textmode = 1;
  191.     else if  (!strcmp(cmd, "binary"))
  192.         textmode = 0;
  193.     else if  (!strcmp(cmd, "mode"))
  194.         switch (textmode)    /* display transfere mode */
  195.         {
  196.         case 0:
  197.             printf("binary\n");
  198.             break;
  199.         case 1:
  200.             printf("text\n");
  201.             break;
  202.         default:
  203.             fprintf(stderr, "corrupted file type.\n");
  204.             exit(2);
  205.         }
  206.     else if  (!strcmp(cmd, "type"))
  207.     {
  208.         int   filetype;
  209.         /* check file type specified */
  210.         switch (toupper(arg[2][0]))
  211.         {
  212.         case 'T': filetype = 0; break;
  213.         case 'I': filetype = 1; break;
  214.         case 'A': filetype = 2; break;
  215.         case 'B': filetype = 4; break;
  216.         case 'S': filetype = 8; break;
  217.         case 'R': filetype = 16; break;
  218.         default : filetype = -1; break;
  219.         }
  220.  
  221.         /* define file type */
  222.         if (filetype<0)
  223.         fprintf(stderr, "filetype %s is invalid.\n", arg[2]);
  224.         else if (!aopen(&d, arg[1], &af, textmode ? "rt" : "rb"))
  225.         fprintf(stderr, "couldn't open ][ file %s\n", arg[1]);
  226.         else
  227.         {
  228.         /* check for locked file */
  229.         if (byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) & 0x80)
  230.             fprintf(stderr, "%s is locked.\n", arg[1]);
  231.         else /* find file and change type */
  232.         {
  233.             byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) = filetype;
  234.             any_unsaved_changes = TRUE;
  235.         }
  236.  
  237.         if (aclose(&af) == EOF)
  238.             fprintf(stderr, "error on closing ][ file %s\n", arg[1]);
  239.         }
  240.     }
  241.     else if (!strcmp(cmd, "reorder"))
  242.     {
  243.         int t, s;
  244.         void* temp;
  245.  
  246.         for (t = 0; t < d.tracks_per_disk; t++)
  247.         {
  248.         for (s = 1; s < d.sectors_per_track / 2; s++)
  249.         {
  250.             temp = d.track[t].sector[s];
  251.             d.track[t].sector[s] =
  252.                 d.track[t].sector[d.sectors_per_track - s - 1];
  253.             d.track[t].sector[d.sectors_per_track - s - 1] = temp;
  254.         }
  255.         }
  256.         any_unsaved_changes = TRUE;
  257.     }
  258.     else if (!strcmp(cmd, "lock") || !strcmp(cmd, "unlock"))
  259.     {
  260.         /* find file and lock/unlock it */
  261.         if (!aopen(&d, arg[1], &af, textmode ? "rt" : "rb"))
  262.         fprintf(stderr, "couldn't find ][ file %s\n", arg[1]);
  263.         else
  264.         {
  265.         if (!strcmp(cmd, "lock"))
  266.             byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) |= 0x80;
  267.         else
  268.             byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) &= 0x7F;
  269.         any_unsaved_changes = TRUE;
  270.         }
  271.  
  272.         if (aclose(&af) == EOF)
  273.         fprintf(stderr, "error on closing ][ file %s\n", arg[1]);
  274.     }
  275.     else if (!strcmp(cmd, "rename"))
  276.     {
  277.         /* check for existing file name */
  278.         if (aopen(&d, arg[2], &af, textmode ? "rt" : "rb"))
  279.         {
  280.         fprintf(stderr, "couldn't rename file %s\n", arg[2]);
  281.         fprintf(stderr, "%s already exists!\n", arg[2]);
  282.         if (aclose(&af) == EOF)
  283.             fprintf(stderr, "error on closing ][ file %s\n", arg[2]);
  284.         }
  285.         else if (!aopen(&d, arg[1], &af, textmode ? "rt" : "rb"))
  286.         fprintf(stderr, "couldn't open ][ file %s\n", arg[1]);
  287.         else
  288.         {
  289.             /* check for locked file */
  290.         if (byteat(af.d, af.dir_t, af.dir_s, af.dir_off+2) & 0x80)
  291.             fprintf(stderr, "%s is locked.\n", arg[1]);
  292.         else /* rename file */
  293.         {
  294.             aputfilename(arg[2], af.d, af.dir_t, af.dir_s, af.dir_off);
  295.             any_unsaved_changes = TRUE;
  296.         }
  297.  
  298.         if (aclose(&af) == EOF)
  299.             fprintf(stderr, "error on closing ][ file %s\n", arg[1]);
  300.         }
  301.     }
  302.     else if (!strcm